package io.gitee.tooleek.lock.spring.boot.service.impl.redis;

import io.gitee.tooleek.lock.spring.boot.core.key.LockKey;
import io.gitee.tooleek.lock.spring.boot.core.key.RedisLockKey;
import io.gitee.tooleek.lock.spring.boot.exception.LockFailException;
import io.gitee.tooleek.lock.spring.boot.exception.LockTimeoutException;
import io.gitee.tooleek.lock.spring.boot.service.LockService;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

/**
 * 公平锁操作服务
 *
 * @author TanRq
 */
public class FairLockServiceImpl implements LockService {

    @Qualifier("lockRedissonClient")
    @Autowired
    private RedissonClient lockRedissonClient;

    private RedisLockKey lockKey;

    private RLock lock;

    @Override
    public void setLockKey(LockKey lockKey) {
        this.lockKey = (RedisLockKey) lockKey;
    }

    @Override
    public void lock() throws Exception {

        this.lock = lockRedissonClient.getFairLock(lockKey.getKeyList().get(0));

        if (lockKey.getLeaseTime() == -1 && lockKey.getWaitTime() == -1) {
            lock.lock();
            return;
        }
        if (lockKey.getLeaseTime() != -1 && lockKey.getWaitTime() == -1) {
            lock.lock(lockKey.getLeaseTime(), lockKey.getTimeUnit());
            return;
        }

        if (lockKey.getLeaseTime() == -1 && lockKey.getWaitTime() != -1) {
            boolean isLock = lock.tryLock(lockKey.getWaitTime(), lockKey.getTimeUnit());
            if (!isLock) {
                throw new LockTimeoutException("获取锁超时");
            }
            return;
        }

        if (lockKey.getLeaseTime() != -1 && lockKey.getWaitTime() != -1) {
            boolean isLock = lock.tryLock(lockKey.getWaitTime(), lockKey.getLeaseTime(), lockKey.getTimeUnit());
            if (!isLock) {
                throw new LockTimeoutException("加锁失败");
            }
            return;
        }

        this.lock.lock();
    }

    @Override
    public void release() {
        this.lock.forceUnlock();
        //this.lock.unlock();
    }

}
